package com.kevin.util;

import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.PDFToImage;
import org.apache.pdfbox.tools.TextToPDF;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
import org.apache.pdfbox.util.Matrix;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * kevin<br/>
 * 2020/10/28 15:38<br/>
 */
public class Img2PdfUtil {

    private static final Logger logger = LoggerFactory.getLogger(Img2PdfUtil.class);

    // 一张600MS
    public static void main(String[] args) throws IOException {
        String source = "C:\\Users\\kevin\\Desktop\\New+Folder\\109042021072000001366.pdf";
        String desDir = "C:\\Users\\kevin\\Desktop\\New+Folder\\pdfbox";

        List<String> filePaths = Arrays.asList(
//                "C:\\Users\\kevin\\Desktop\\移动审批问题排查\\109012022032300002852.jpg",
                "C:\\Users\\kevin\\Desktop\\移动审批问题排查\\template2.jpg"
//                "C:\\Users\\kevin\\Desktop\\移动审批问题排查\\109012022061000002039.jpg",
//                "C:\\Users\\kevin\\Desktop\\移动审批问题排查\\109012022061000002040.jpg",
//                "C:\\Users\\kevin\\Desktop\\移动审批问题排查\\109012022061000002041.jpg",
//                "C:\\Users\\kevin\\Desktop\\移动审批问题排查\\109012022061000002042.jpg",
//                "C:\\Users\\kevin\\Desktop\\移动审批问题排查\\109012022061400000711.png"
        );
        String des = "C:\\Users\\kevin\\Desktop\\移动审批问题排查\\";

//        String textfile = "C:\\Users\\kevin\\Desktop\\pdf2jpg.txt";
//        String outputfile = "D:\\测试PDF\\test2.pdf";

        long start = System.currentTimeMillis();
//        pdf2jpgTool(source, desDir);
//        System.out.println(JsonUtil.bean2Json(pdf2jpg(source, desDir)));
        jpg2pdf(filePaths, des, "（12时45分44秒归档）2022-06-14测试PDF\\JPG.pdf");
//        text2pdf(textfile, outputfile);
        System.out.println((System.currentTimeMillis() - start) + "ms");
    }

    private static void text2pdf(String textfile, String outputfile) throws IOException {
        TextToPDF.main(new String[]{"-ttf", "C:\\Windows\\Fonts\\simfang.ttf", outputfile, textfile});
    }

    /**
     * java -jar pdfbox-app-2.0.2.jar ExtractText -startPage 4 -endPage 13 Gradle.in.Action.pdf gradle.txt
     */
    private static void pdf2jpgTool(String source, String desDir) throws IOException {
        PDFToImage.main(new String[]{"-outputPrefix", desDir + "测试", "-time", source});
    }

    /**
     * pdf转换jpg
     * @param filePath  源文件绝对路径
     * @param desDir    目标文件夹绝对路径，用于存放转换后的jpg
     * @return          转换后的jpg绝对路径列表
     */
    public static List<String> pdf2jpg(String filePath, String desDir) throws IOException {
        Path sourcePath = Paths.get(filePath);
        if (Files.notExists(sourcePath)) {
            throw new FileNotFoundException(filePath);
        }
        String filename = filePath.substring(filePath.lastIndexOf(File.separator) + 1,
                filePath.lastIndexOf("."));
        Path desDirPath = Paths.get(desDir);
        List<String> desFilePaths = new ArrayList<>();

        long start = System.currentTimeMillis();

        // 根据PDFBox的提示，设置此项以提高渲染性能
        System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");

        try (InputStream is = Files.newInputStream(sourcePath);
             PDDocument doc = PDDocument.load(is, MemoryUsageSetting.setupMainMemoryOnly())) {
            PDFRenderer renderer = new PDFRenderer(doc);
            String desFilePath;
            List<DesPage> desPages = new ArrayList<>();
            int pageCount = doc.getNumberOfPages();
            for (int i = 0; i < pageCount; i++) {
                desFilePath = desDirPath + File.separator + filename + "_" + i + ".jpg";
                desFilePaths.add(desFilePath);
                desPages.add(new DesPage(i, desFilePath));
            }

            desPages.parallelStream().forEach(desPage -> {
                try {
                    BufferedImage image = renderer.renderImageWithDPI(desPage.getPageNum(), 120);
                    ImageIOUtil.writeImage(image, desPage.getFilePath(), 120);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }

        logger.info("pdf2jpg耗时" + (System.currentTimeMillis() - start) + "ms");
        return desFilePaths;
    }

    /**
     * jpg转pdf
     * @param filePaths             源文件绝对路径列表
     * @param desDir                目标文件夹绝对路径，用于存放转换后的pdf
     * @param desFilename           转换后的pdf文件名
     * @return                      转换后的pdf绝对路径
     */
    public static String jpg2pdf(List<String> filePaths, String desDir, String desFilename) throws IOException {
        List<Path> paths = new ArrayList<>();
        for (String filePath : filePaths) {
            Path path = Paths.get(filePath);
            if (Files.notExists(path)) {
                logger.error("文件不存在" + path);
                throw new FileNotFoundException(filePath);
            } else {
                paths.add(path);
            }
        }

        // 去掉文件名中可能存在的正反斜杠(此为不规范文件名，但可能无法避免)
        String desFilePath = desDir + File.separator + desFilename
                .replaceAll("/", "").replaceAll("\\\\", "");

        long start = System.currentTimeMillis();

        try (PDDocument doc = new PDDocument()) {
            for (Path path : paths) {
                PDPage page = new PDPage(PDRectangle.A4);
                doc.addPage(page);
                PDImageXObject pdImage = PDImageXObject.createFromFile(path.toString(), doc);
                PDPageContentStream content = new PDPageContentStream(doc, page);
                PDRectangle rectangle = page.getMediaBox();

                float scale = Math.min(rectangle.getWidth() / pdImage.getWidth(),
                        rectangle.getHeight() / pdImage.getHeight());
                if (scale > 1.0f) {
                    scale = 1.0f;
                }
                // startX和startY注意要除以缩放比例，因为经过Matrix.getScaleInstance后，startX和startY会被等比例缩放
                float startX = ((rectangle.getWidth() - pdImage.getWidth() * scale) / 2) / scale;
                float startY = ((rectangle.getHeight() - pdImage.getHeight() * scale) / 2) / scale;
                content.transform(Matrix.getScaleInstance(scale, scale));
                content.drawImage(pdImage, startX, startY);
                content.close();
            }
            doc.save(desFilePath);
        }

        logger.info("jpg2pdf耗时" + (System.currentTimeMillis() - start) + "ms");
        return desFilePath;
    }
}

